package com.welike.shibo.controller.api;

import com.alibaba.fastjson.JSONObject;
import com.welike.shibo.aspect.annotation.AutoLog;
import com.welike.shibo.controller.BaseController;
import com.welike.shibo.eneity.JsonResult;
import com.welike.shibo.eneity.Log;
import com.welike.shibo.eneity.LoginUser;
import com.welike.shibo.eneity.User;
import com.welike.shibo.enums.ResultEnum;
import com.welike.shibo.service.*;
import com.welike.shibo.utils.PasswordEncrypt;
import com.welike.shibo.utils.ResultUtils;
import com.welike.shibo.utils.Tools;
import com.welike.shibo.vo.UserInfoVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.NoSuchAlgorithmException;
import java.util.Date;

/**
 * @author fangyu
 * @version v1.0.0
 * @since 2019-08-21 03:17
 */

@Slf4j
@Api(value = "登录、注册接口")
@RestController
@RequestMapping("/api")
public class ApiIndexController extends BaseController {

    @Resource
    private SmsService smsService;

    @Autowired
    private UserService userService;

    @Autowired
    private LogService logService;

    @Autowired
    private ShopHttpService shopHttpService;

    @Autowired
    private RedisService redisService;

    @Value("${redis.key.phone}")
    private String REDIS_KEY_PHONE;

    @Value("${redis.key.reset}")
    private String REDIS_KEY_RESET;

//    @Autowired
//    private JwtUtil jwtUtil;

    /**
     * 发送验证码
     *
     * @param request 获取session
     * @param phone   手机号
     * @return JsonResult
     */
    @AutoLog(operateType = "APP", operateState = "获取验证码")
    @ApiOperation(value = "发送短信验证码", notes = "输入手机号发送短信验证码")

    @PostMapping("/sms")
    public JsonResult sendSms(
            HttpServletRequest request,
            @RequestParam(name = "phone") String phone,
            @RequestParam(name = "type", required = false, defaultValue = "1") String type
    ) {
        map.clear();
        map.put("path", "/api/sms");
        try {
            if (Tools.isNull(phone)) {
                return ResultUtils.error(ResultEnum.PHONE_DONT_NOT_NULL.getCode(), ResultEnum.PHONE_DONT_NOT_NULL.getMsg(), map);
            }
            if (!Tools.isMobile(phone)) {
                return ResultUtils.error(ResultEnum.PHONE_ERROR.getCode(), ResultEnum.PHONE_ERROR.getMsg(), map);
            }
            int code = Tools.generateSmsCode();
            if ("1".equals(type)) {
                redisService.set(REDIS_KEY_PHONE + phone, String.valueOf(code));
                redisService.expire(REDIS_KEY_PHONE + phone, 1800);
                smsService.sendMsgForRegisterToTencent(phone, code);
                map.put("type", "register");
                if (userService.queryPhoneByPhone(phone)) {
                    return ResultUtils.error(ResultEnum.PHONE_REGISTER.getCode(), ResultEnum.PHONE_REGISTER.getMsg(), map);
                }
            } else if ("2".equals(type)) {
                redisService.set(REDIS_KEY_RESET + phone, String.valueOf(code));
                redisService.expire(REDIS_KEY_RESET + phone, 1800);
                smsService.sendMsgForChangePwdToTencent(phone, code);
                map.put("type", "change_pwd");
            }
        } catch (Exception e) {
            log.error("sendSms error: {}", e.getMessage());
            return ResultUtils.error(e.getMessage());
        }
        return ResultUtils.success(map);
    }


    /**
     * 注册验证
     *
     * @param request 请求信息
     * @param phone   手机号
     * @param code    验证码
     * @return JsonResult
     */
    @AutoLog(operateType = "APP", operateState = "注册")
    @ApiOperation(value = "注册", notes = "输入手机号, 验证码, 密码进行注册")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "phone", value = "手机号", required = true),
            @ApiImplicitParam(paramType = "query", name = "code", value = "验证码", required = true),
            @ApiImplicitParam(paramType = "query", name = "password", value = "密码", required = true),})
    @PostMapping("/register")
    public JsonResult register(
            HttpServletRequest request,
            @RequestParam(name = "phone") String phone,
            @RequestParam(name = "code") String code,
            @RequestParam(name = "password") String password
    ) throws NoSuchAlgorithmException {
        log.info("phone:{}, code:{}, password:{}", phone, code, password);
        map.clear();
        map.put("path", "/api/register");
        try {
            // 手机号不可为空
            if (Tools.isNull(phone)) {
                return ResultUtils.error(ResultEnum.PHONE_DONT_NOT_NULL.getCode(), ResultEnum.PHONE_DONT_NOT_NULL.getMsg(), map);
            }
            // 手机号检测
            if (!Tools.isMobile(phone)) {
                return ResultUtils.error(ResultEnum.PHONE_ERROR.getCode(), "手机号码格式不正确!", map);
            }
            // 验证手机号是否被注册
            if (userService.queryPhoneByPhone(phone)) {
                return ResultUtils.error(ResultEnum.PHONE_REGISTER.getCode(), ResultEnum.PHONE_REGISTER.getMsg(), map);
            }
            String checkCode = redisService.get(REDIS_KEY_PHONE + phone);
            log.info("checkCode in Redis ==> {}", checkCode);
//            if (request.getSession().getAttribute(phone) == null) {
            if (checkCode == null) {
                return ResultUtils.error(ResultEnum.CAPTCHA_ERROR.getCode(), "请先获取验证码", map);
            }
//            String checkCode = request.getSession().getAttribute(phone).toString();
//            log.info("session => {}", checkCode);
//            log.info("session => {}", request.getSession().getAttribute(phone));
            // 判断有没有获取验证码
            // 验证码检测
            if (!checkCode.equals(code)) {
                return ResultUtils.error(ResultEnum.CAPTCHA_ERROR.getCode(), ResultEnum.CAPTCHA_ERROR.getMsg(), map);
            }
            if (Tools.isNull(password)) {
                return ResultUtils.error(ResultEnum.PASSWORD_DONT_NOT_NULL.getCode(), ResultEnum.PASSWORD_DONT_NOT_NULL.getMsg(), map);
            }
            // 生成uid(用户唯一id) todo 待完成生成唯一uid方法
            String uid = Tools.generateShortUid();
            log.info("generate UUID: {}", uid);
            Integer level = shopHttpService.getUserLevelByPhone(phone);
            User user = new User(uid, phone, PasswordEncrypt.encodeByMd5(password), level, new Date());
            // 如果结果为空，则注册失败
            if (!userService.save(user)) {
                return ResultUtils.error(ResultEnum.REGISTER_ERROR.getCode(), ResultEnum.REGISTER_ERROR.getMsg(), map);
            }
            map.put("uid", uid);
            map.put("phone", phone);
            // 成功后从session中删除验证码信息
            request.getSession().removeAttribute(phone);
            logService.save(new Log(uid, "注册账号:" + phone, new Date()));
        } catch (Exception e) {
//            throw new BaseException(ResultEnum.REGISTER_ERROR);
            log.debug(e.getMessage());
            return ResultUtils.error(ResultEnum.REGISTER_ERROR.getCode(), "注册失败", map);
        }
        return ResultUtils.success("注册成功", map);
    }

    /**
     * 登录, 登录成功, 设置session或token
     * 这里使用用户id来生成token
     *
     * @param
     * @return
     */
    @AutoLog(operateType = "APP", operateState = "登录")
    @ApiOperation(value = "登录", notes = "输入手机号, 密码/验证码登录")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "phone", value = "手机号", required = true),
            @ApiImplicitParam(paramType = "query", name = "code", value = "验证码", required = false),
            @ApiImplicitParam(paramType = "query", name = "password", value = "密码", required = false),
            @ApiImplicitParam(paramType = "query", name = "type", value = "登录方式, 1-短信, 2-密码", required = true),
            @ApiImplicitParam(paramType = "query", name = "deviceId", value = "设备标识, 设备Id", required = false),
            @ApiImplicitParam(paramType = "query", name = "deviceType", value = "设备操作系统", required = false)})
    @PostMapping("/login")
    public JsonResult login(
            HttpServletResponse response,
            @RequestParam(value = "phone") String phone,
            @RequestParam(value = "code", required = false) String code,
            @RequestParam(value = "password", required = false) String password,
            @RequestParam(value = "type", required = true, defaultValue = "2") Integer type,
            @RequestParam(value = "device_id", required = false) String deviceId,
            @RequestParam(value = "device_type", required = false) String deviceType
    ) throws NoSuchAlgorithmException {
        map.clear();
        map.put("path", "/api/login");
        LoginUser user = null;
        String uid = null;
        log.info("login type ==> {}", type);
        try {
            // 手机号不可为空
            if (phone == null) {
                return ResultUtils.error(ResultEnum.PHONE_DONT_NOT_NULL.getCode(), ResultEnum.PHONE_DONT_NOT_NULL.getMsg(), map);
            }
            // 手机号检测
            if (!Tools.isMobile(phone)) {
                return ResultUtils.error(ResultEnum.PHONE_ERROR.getCode(), ResultEnum.PHONE_ERROR.getMsg(), map);
            }
            // 账号状态检测, 并确定手机号是否存在
            Integer status = userService.queryStatusByPhone(phone);
            if (status == null) {
                return ResultUtils.error(ResultEnum.USER_NOT_EXIST.getCode(), ResultEnum.USER_NOT_EXIST.getMsg(), map);
            }
            // 手机账号状态
            if (status != 1) {
                return ResultUtils.error(ResultEnum.PHONE_ERROR.getCode(), "账号已被禁用!请联系管理员解禁!", map);
            }
            // 手机号注册检测，验证手机号是否注册, 没有注册则提示未注册
            if (!userService.queryPhoneByPhone(phone)) {
                return ResultUtils.error(ResultEnum.USER_NOT_EXIST.getCode(), ResultEnum.USER_NOT_EXIST.getMsg(), map);
            }
            // 判断登录类型，1位用验证码登录，2为用密码登录
            if (type == 1) {
//                String checkCode = request.getSession().getAttribute(phone).toString();
                String checkCode = "123456";
                if (Tools.isNull(checkCode) || !checkCode.equals(code)) {
                    return ResultUtils.error(ResultEnum.CAPTCHA_ERROR.getCode(), ResultEnum.CAPTCHA_ERROR.getMsg(), map);
                }
                // 如果验证码无误则登录成功, 然后通过手机号查询用户信息并返回
                user = userService.queryUserByPhone(phone);
            } else if (type == 2) {
                log.info("");
                // 类型为2用密码登录, 查询用户密码是否一样
                if (StringUtils.isEmpty(password)) {
                    return ResultUtils.error(ResultEnum.PASSWORD_DONT_NOT_NULL.getCode(), ResultEnum.PASSWORD_DONT_NOT_NULL.getMsg(), map);
                }
                // TODO 查询结果然后判断
                user = userService.queryUserInfoByPhoneAndPwd(phone, PasswordEncrypt.encodeByMd5(password));
                // 如果查询结果为空，密码错误，还是用户不存在另说
                if (user == null) {
                    return ResultUtils.error(ResultEnum.PASSWORD_ERROR.getCode(), ResultEnum.PASSWORD_ERROR.getMsg(), map);
                }
                uid = user.getUid();
            } else {
                // 其他类型直接返回参数错误
                return ResultUtils.error(ResultEnum.PARAM_ERROR.getCode(), ResultEnum.PARAM_ERROR.getMsg(), map);
            }
            // 登录成功，更新设备信息
            log.info("deviceId ==> {}, deviceType ==> {}", deviceId, deviceType);
            userService.updateDeviceInfoByUid(deviceId, deviceType, uid);
            // 增加日志记录
            logService.save(new Log(user.getUid(), "登录APP", new Date()));
        } catch (Exception e) {
            log.error("login error Exception:{}", e.getMessage());
            return ResultUtils.error(404, e.getMessage(), map);
        }
//        map.put("userInfo", user);
        // 设置session或者token
        setSession(user);
        log.info("set Session user: {}", user);
        UserInfoVO userInfoVO = userService.queryUserInfo(uid);
        map.put("user", userInfoVO);
        // 最后放入token
//                map.put("token", jwtUtil.generateToken(userId+""));
        return ResultUtils.success("登录成功!", map);
    }

    /**
     * 退出登录, 清空session
     *
     * @return JsonResult
     */
    @ApiOperation(value = "登出", notes = "退出登录")
    @PostMapping("/logout")
    public JsonResult logout() {
        map.clear();
        map.put("path", "/api/logout");
        LoginUser user = (LoginUser) getUser4Session();
        if (user == null) {
            return ResultUtils.error(ResultEnum.NOT_LOGIN.getCode(), ResultEnum.NOT_LOGIN.getMsg(), map);
        }
        emptySession(null);
        log.info("user session ==> {}", getUser4Session());
        logService.save(new Log(user.getUid(), "退出手机登录", new Date()));
        return ResultUtils.success("已退出登录!", map);
    }

    @ApiOperation(value = "验证码校验", notes = "验证码校验")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "phone", value = "手机号", required = true),
            @ApiImplicitParam(paramType = "query", name = "code", value = "验证码", required = true)})
    @PostMapping("/sms/check")
    public JsonResult resetPwdSmsCheck(
            @RequestParam(name = "phone") String phone,
            @RequestParam(name = "code") String code
    ) {
        return smsService.resetPwdCheckSms(phone, code);
    }

    @AutoLog(operateType = "APP", operateState = "重置密码")
    @ApiOperation(value = "忘记密码", notes = "忘记密码")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "phone", value = "手机号", required = true),
            @ApiImplicitParam(paramType = "query", name = "password", value = "新的密码", required = true)})
    @PostMapping("/reset")
    public JsonResult resetPwd(
            @RequestParam(name = "phone") String phone,
            @RequestParam(name = "password") String pwd
    ){
        return userService.resetPwd(phone, pwd);
    }

    @GetMapping("/version/android")
    public JsonResult getAndroidVersion(){
        String value = redisService.get("version");
        JSONObject result = JSONObject.parseObject(value);
        return ResultUtils.success(result);
    }

}